#include "common.h"

struct Message {
	int64_t request;
	int64_t response;
};


int server = 0;
char hostname[32];
int port = 8000;

void server_routine();
void client_routine();
void* sender(void*);

int main(int argc, char* argv[]) {
	Args args = parsecmdline(argc, argv);
	if (args.empty() || args.find("h") == args.end()) {
		printf("Usage: %s [-s] <-h hostname> [-p port]\n", argv[0]);
		return 1;
	}

	strcpy(hostname, args["h"].c_str());
	if (args.find("p") != args.end()) port = atoi(args["p"].c_str());
	if (args.find("s") != args.end()) server = 1;

	if (server) {
		server_routine();
	}
	else {
		client_routine();
	}
}

void server_routine() {
	int serverfd, len, ret;
	Message msg;
	sockaddr_in servaddr, cliaddr;
	socklen_t cliaddrlen;

	servaddr = resolve(hostname, port);
	
	serverfd = socket(AF_INET, SOCK_DGRAM, 0);
	if (serverfd < 0) ERR_EXIT("socket");

	ret = bind(serverfd, (struct sockaddr*)&servaddr, sizeof(servaddr));
	if (ret < 0) ERR_EXIT("bind");

	while(1) {
		cliaddrlen = sizeof(cliaddr);
		len = recvfrom(serverfd, &msg, sizeof(msg), 0, (struct sockaddr*)&cliaddr, &cliaddrlen);
		assert(len == sizeof(msg));
		if (len < 0) {
			if (errno == EINTR) continue;
			ERR_EXIT("recvfrom");
		}
		msg.response = now();
		len = sendto(serverfd, &msg, sizeof(msg), 0, (struct sockaddr*)&cliaddr, cliaddrlen);
		assert(len == sizeof(msg));
	}
}


void client_routine() {
	int clientfd, ret, len;
	int64_t back, mine;
	Message msg;
	sockaddr_in servaddr;
	pthread_t th;


	clientfd = socket(AF_INET, SOCK_DGRAM, 0);
	if (clientfd < 0) ERR_EXIT("socket");
	
	// 起线程是防止怕报方丢失了，接收的时候死等
	ret = pthread_create(&th, NULL, sender, &clientfd); 
	if (ret < 0) ERR_EXIT("pthread_create");

	while(1) {
		len = recvfrom(clientfd, &msg, sizeof(msg), 0, NULL, NULL);
		assert(len == sizeof(msg));
		back = now();
		mine = ((back + msg.request) >> 1);
		printf("now: %jd, round trip: %jd, clock error: %jd\n"
			, back, back - msg.request, msg.response - mine);
	}
}

void* sender(void* arg) {
	sockaddr_in servaddr;
	int clientfd, len;
	Message msg;

  clientfd = *(int*)arg;
	servaddr = resolve(hostname, port);

	while(1) {
		msg.request = now();
		len = sendto(clientfd, &msg, sizeof(msg), 0, (struct sockaddr*)&servaddr, sizeof(servaddr)); 
		assert(len == sizeof(msg));
		usleep(500*1000);
	}
}
